<script setup lang="ts">
import type { PlusDialogFormInstance } from "plus-pro-components";
import { reactive, ref, watch, nextTick } from "vue";
import { zxcvbn } from "@zxcvbn-ts/core";
import { isAllEmpty } from "@pureadmin/utils";
import { message } from "@/utils/message";
import $request from "../request";
import { PlusColumn } from "plus-pro-components";

// 定义事件
const emit = defineEmits(["ok"]);

// 状态参数
const state = reactive({
  // 密码类型
  passType: "",
  // 提交中
  confirmLoading: false,
  // 是否显示
  visible: false
});

// 表单数据
const formData = ref({
  oldPassword: "",
  newPassword: "",
  confirmPassword: ""
});

// 组件
const plusDialogFormRef = ref<PlusDialogFormInstance | null>();

// 当前密码强度（0-4）
const curScore = ref();

const pwdProgress = [
  { color: "#e74242", text: "非常弱" },
  { color: "#EFBD47", text: "弱" },
  { color: "#ffa500", text: "一般" },
  { color: "#1bbf1b", text: "强" },
  { color: "#008000", text: "非常强" }
];

const rules = {
  oldPassword: [
    {
      required: true,
      message: "请输入原密码"
    }
  ],
  newPassword: [
    {
      required: true,
      message: "请输入新密码"
    }
  ],
  confirmPassword: [
    {
      required: true,
      message: "请输入新密码"
    },
    {
      validator: (rule: any, value: string, callback: any) => {
        if (value === "") {
          callback(new Error("请输入新密码"));
        } else if (value !== formData.value.newPassword) {
          callback(new Error("两次输入的密码不一致"));
        } else {
          callback();
        }
      },
      trigger: "blur"
    }
  ]
};

const columns: PlusColumn[] = [
  {
    label: "原密码",
    prop: "oldPassword",
    valueType: "input",
    fieldProps: {
      type: "password",
      showPassword: true
    }
  },
  {
    label: "新密码",
    prop: "newPassword",
    valueType: "input",
    fieldProps: {
      type: "password",
      showPassword: true
    }
  },
  {
    label: "重复输入",
    prop: "confirmPassword",
    valueType: "input",
    fieldProps: {
      type: "password",
      showPassword: true
    }
  }
];

// 弹窗开启
const handleOpen = async () => {
  state.passType = "password";
  state.confirmLoading = false;
  state.visible = true;
};

// 提交
const handleSubmit = async () => {
  try {
    state.confirmLoading = true;
    await $request.put.changePassword(
      formData.value.oldPassword,
      formData.value.newPassword
    );
    message("密码修改成功, 请牢记新密码", { type: "success" });
    emit("ok");
    handleCancel();
  } finally {
    state.confirmLoading = false;
  }
};

// 取消
const handleCancel = async () => {
  state.visible = false;
  await nextTick();
  formData.value.oldPassword = "";
  formData.value.newPassword = "";
  formData.value.confirmPassword = "";
  setTimeout(() => {
    plusDialogFormRef.value?.formInstance.clearValidate();
  }, 300);
};

// 计算密码强度
watch(
  () => formData.value.newPassword,
  val => (curScore.value = isAllEmpty(val) ? -1 : zxcvbn(val).score)
);

defineExpose({
  handleOpen
});
</script>

<template>
  <plus-dialog-form
    ref="plusDialogFormRef"
    v-model:visible="state.visible"
    v-model="formData"
    :form="{
      columns,
      labelWidth: '90px',
      labelPosition: 'right',
      rules,
      rowProps: { gutter: 15 },
      colProps: { span: 24 }
    }"
    :dialog="{
      title: '修改密码',
      width: '400px',
      top: '12vh',
      closeOnClickModal: true,
      confirmLoading: state.confirmLoading
    }"
    @confirm="handleSubmit"
    @cancel="handleCancel"
  >
    <template #plus-extra-confirmPassword>
      <div class="flex pt-5">
        <template v-for="(item, index) of pwdProgress" :key="index">
          <div
            class="w-[19vw]"
            :style="{ marginLeft: index !== 0 ? '4px' : 0 }"
          >
            <el-progress
              striped
              striped-flow
              :duration="curScore === index ? 6 : 0"
              :percentage="curScore >= index ? 100 : 0"
              :color="item.color"
              :stroke-width="10"
              :show-text="false"
            />

            <p
              class="text-center"
              :style="{ color: curScore === index ? item.color : '' }"
            >
              {{ item.text }}
            </p>
          </div>
        </template>
      </div>
    </template>
  </plus-dialog-form>
</template>

<style lang="scss" scoped>
//
</style>
